package cn.zyx.common.utils.sys.log;

import cn.zyx.common.properites.CacheProperties;
import cn.zyx.common.utils.cache.ehcache.CacheUtils;
import cn.zyx.common.utils.sys.SpringContextHolderUtils;
import cn.zyx.sys.entity.Log;
import cn.zyx.sys.entity.Menu;
import cn.zyx.sys.mapper.LogMapper;
import cn.zyx.sys.mapper.MenuMapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.method.HandlerMethod;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

/**
 * 异步保持日志线程
 */
public class SaveLogThread extends Thread{

    private final Log log;
    private final Object handler;
    private final Exception ex;

    public SaveLogThread(Log log, Object handler, Exception ex){
        super(SaveLogThread.class.getSimpleName()); // 线程名称
        this.log = log;
        this.handler = handler;
        this.ex = ex;
    }

    @Override
    public void run() {
        // 获取日志标题
        if (StringUtils.isBlank(log.getTitle())){
            String permission = "";
            if (handler instanceof HandlerMethod){
                Method m = ((HandlerMethod)handler).getMethod();
                RequiresPermissions rp = m.getAnnotation(RequiresPermissions.class);
                permission = (rp != null ? StringUtils.join(rp.value(), ",") : "");
            }
            log.setTitle(getMenuNamePath(log.getRequestUri(), permission));
        }

        // 如果有异常，设置异常信息
        log.setException(getStackTraceAsString(ex));

        // 如果无标题并无异常日志，则不保存信息hxw2021 0831
        if (StringUtils.isBlank(log.getTitle()) ){
            return;
        }

        // 保存日志信息
        log.preInsert();

        SpringContextHolderUtils.getBean(LogMapper.class).insert(log);
    }


    /**
     * 获取菜单名称路径（如：系统设置-机构用户-用户管理-编辑）
     */
    public static String getMenuNamePath(String requestUri, String permission){
        @SuppressWarnings("unchecked")
        Map<String, String> menuMap = (Map<String, String>) CacheUtils.get(CacheProperties.CACHE_MENU_NAME_PATH_MAP);
        if (menuMap == null){
            menuMap = Maps.newHashMap();
            List<Menu> menuList = SpringContextHolderUtils.getBean(MenuMapper.class).findAllList(new Menu());
            for (Menu menu : menuList){
                // 获取菜单名称路径（如：系统设置-机构用户-用户管理-编辑）
                String namePath = "";
                if (menu.getParentIds() != null){
                    List<String> namePathList = Lists.newArrayList();
                    for (String id : StringUtils.split(menu.getParentIds(), ",")){
                        if (Menu.getRootId().equals(id)){
                            continue; // 过滤跟节点
                        }
                        for (Menu m : menuList){
                            if (m.getId().equals(id)){
                                namePathList.add(m.getName());
                                break;
                            }
                        }
                    }
                    namePathList.add(menu.getName());
                    namePath = StringUtils.join(namePathList, "-");
                }
                // 设置菜单名称路径
                if (StringUtils.isNotBlank(menu.getHref())){
                    menuMap.put(menu.getHref(), namePath);
                }else if (StringUtils.isNotBlank(menu.getPermission())){
                    for (String p : StringUtils.split(menu.getPermission())){
                        menuMap.put(p, namePath);
                    }
                }

            }
            CacheUtils.put(CacheProperties.CACHE_MENU_NAME_PATH_MAP, menuMap);
        }
        // 获取菜单名称路径
        String menuNamePath = menuMap.get(requestUri);
        if (menuNamePath == null){
            for (String p : StringUtils.split(permission,",")){//hxw2021 0831菜单权限
                menuNamePath = menuMap.get(p);
                if (StringUtils.isNotBlank(menuNamePath)){
                    break;
                }
            }
            if (menuNamePath == null){
                return "";
            }
        }
        return menuNamePath;
    }


    /**
     * 将ErrorStack转化为String.
     */
    public static String getStackTraceAsString(Throwable e) {
        if (e == null){
            return "";
        }
        StringWriter stringWriter = new StringWriter();
        e.printStackTrace(new PrintWriter(stringWriter));
        return stringWriter.toString();
    }
}
